home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / pmake / customs / customs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-11-15  |  19.4 KB  |  766 lines

  1. /*-
  2.  * customs.c --
  3.  *    A server to inform clients, using RPC, where they can send
  4.  *    processes.
  5.  *
  6.  *    Each machine that wishes to export processes must have
  7.  *    a server running. The first server to start is the
  8.  *    Master Customs Agent (MCA), while everything else is a
  9.  *    Slave Customs Agent (SCA).
  10.  *
  11.  *    The job of the MCA is to track the availability of machines
  12.  *    running SCA's and allocate them to other SCA's as necessary.
  13.  *
  14.  *    An SCA is responsible for sampling its host's status from
  15.  *    time to time to see if it can accept processes from other
  16.  *    machines. This information must be provided to the MCA
  17.  *    at regular intervals.
  18.  *
  19.  *    An SCA can specify which hosts it is willing to serve for
  20.  *    (there must be at least one) and the MCA will only allocate
  21.  *    it to one of the hosts in that list. A host will not be allocated
  22.  *    to an SCA again until all other available hosts which serve
  23.  *    the requesting SCA have been used.
  24.  *
  25.  *    Several procedures are provided to clients of the customs agents.
  26.  *    The CUSTOMSPROC_HOST will return a structure containing the address
  27.  *    of a machine on which the exported process may be run. It also
  28.  *    returns an identifying number which must be passed to the serving
  29.  *    machine before it will execute the process. The MCA does not guarantee
  30.  *    that the serving machine is actually up, though it tries hard to
  31.  *    ensure this. If the machine has a long interval between availability
  32.  *    packets, all bets are off.
  33.  *
  34.  * Copyright (c) 1988, 1989 by the Regents of the University of California
  35.  * Copyright (c) 1988, 1989 by Adam de Boor
  36.  * Copyright (c) 1989 by Berkeley Softworks
  37.  *
  38.  * Permission to use, copy, modify, and distribute this
  39.  * software and its documentation for any non-commercial purpose
  40.  * and without fee is hereby granted, provided that the above copyright
  41.  * notice appears in all copies.  The University of California,
  42.  * Berkeley Softworks and Adam de Boor make no representations about
  43.  * the suitability of this software for any purpose.  It is provided
  44.  * "as is" without express or implied warranty.
  45.  *
  46.  */
  47. #ifndef lint
  48. static char *rcsid =
  49. "$Id: customs.c,v 1.22 89/11/14 13:45:56 adam Exp $ SPRITE (Berkeley)";
  50. #endif lint
  51.  
  52. #include    "sprite.h"
  53. #include    "customsInt.h"
  54.  
  55. #include    <sys/file.h>
  56. #include    <errno.h>
  57. #include    <stdio.h>
  58. #include    <sys/ioctl.h>
  59. #include    <strings.h>
  60. #include    <signal.h>
  61. #include    <sys/resource.h>
  62. #include    <netdb.h>
  63.  
  64. char                      localhost[MACHINE_NAME_SIZE];
  65. Boolean                      amMaster;    /* TRUE if this process is MCA */
  66.  
  67. Boolean                      verbose = FALSE;
  68.  
  69. unsigned long                arch;       /* Machine architecture code */
  70. char                      *regPacket;
  71. int                      regPacketLen;
  72. int                      numClients;
  73. char                      **clients;
  74. int                      initARGC;
  75. char                  **initARGV;
  76.  
  77.  
  78. struct timeval    retryTimeOut = {
  79.     CUSTOMSINT_RETRY, CUSTOMSINT_URETRY
  80. };
  81.  
  82. /*
  83.  * Default ports if yellow pages f***s us over
  84.  */
  85. #define DEF_CUSTOMS_UDP_PORT    8231
  86. #define DEF_CUSTOMS_TCP_PORT    8231
  87.  
  88. short                        tcpPort;
  89. int                      tcpSocket;
  90. short                udpPort;
  91. int                      udpSocket;    /* The actual socket to which clients
  92.                      * connect */
  93. struct sockaddr_in        localAddr;    /* Address of local socket */
  94.  
  95. /*-
  96.  *-----------------------------------------------------------------------
  97.  * MakeRegistrationPacket --
  98.  *    Mangles the local host and argument vector into a packet to
  99.  *    be sent to the master at registration time.
  100.  *
  101.  * Results:
  102.  *    None.
  103.  *
  104.  * Side Effects:
  105.  *    regPacket is allocated and filled and regPacketLen is altered.
  106.  *
  107.  *-----------------------------------------------------------------------
  108.  */
  109. static void
  110. MakeRegistrationPacket()
  111. {
  112.     register int  i;
  113.     register char **cpp;
  114.     register char *cp;
  115.     int localhostLen;
  116.  
  117.     localhostLen = (strlen(localhost) + 1 + 3) & ~3;
  118.     regPacketLen = localhostLen + sizeof(long) + sizeof(arch);
  119.     for (i = 0; i < numClients; i++) {
  120.     regPacketLen += strlen(clients[i]) + 1;
  121.     }
  122.     regPacket = (char *)malloc((unsigned)regPacketLen);
  123.     strncpy (regPacket, localhost, localhostLen);
  124.     cp = regPacket + localhostLen;
  125.     *((unsigned long *)cp) = arch;
  126.     cp += sizeof(arch);
  127.     *((long *)cp) = numClients;
  128.     cp += sizeof(long);
  129.  
  130.     for (cpp = clients, i = numClients; i != 0; i--, cpp++) {
  131.     strcpy(cp, *cpp);
  132.     cp += strlen(cp) + 1;
  133.     }
  134. }
  135.  
  136. /*-
  137.  *-----------------------------------------------------------------------
  138.  * CustomsPing --
  139.  *    Do-nothing function to handle the CUSTOMS_PING procedure.
  140.  *
  141.  * Results:
  142.  *    None.
  143.  *
  144.  * Side Effects:
  145.  *    None.
  146.  *
  147.  *-----------------------------------------------------------------------
  148.  */
  149. /*ARGSUSED*/
  150. static void
  151. CustomsPing(from, msg, len, data)
  152.     struct sockaddr_in    *from;
  153.     Rpc_Message          msg;
  154.     int                  len;
  155.     Rpc_Opaque           data;
  156. {
  157.     Rpc_Return(msg, 0, data);
  158. }
  159.  
  160. /*-
  161.  *-----------------------------------------------------------------------
  162.  * CustomsHost --
  163.  *    Stub for handling the CUSTOMS_HOST procedure. Issues
  164.  *    CUSTOMS_HOSTINT call to master. While the master could conceivably
  165.  *    call MCA_HostInt, we don't do that b/c the port number for return
  166.  *    will be wrong. If the flags in the data contain EXPORT_USELOCAL,
  167.  *    the availability of the local machine is checked before the call
  168.  *    is issued.
  169.  *
  170.  * Results:
  171.  *    None.
  172.  *
  173.  * Side Effects:
  174.  *    An ExportPermit is sent in reply.
  175.  *
  176.  *-----------------------------------------------------------------------
  177.  */
  178. static void
  179. CustomsHost(from, msg, len, data)
  180.     struct sockaddr_in    *from;
  181.     Rpc_Message          msg;
  182.     int                  len;
  183.     Rpc_Opaque          data;
  184. {
  185.     ExportPermit        permit;
  186.     Host_Data          *host = (Host_Data *)data;
  187.     long                rating;    /* Junk variable */
  188.  
  189.     /*
  190.      * A CustomsHost call must come from the local host to
  191.      * keep people from requesting from a different machine, not
  192.      * that it would work anyway, since the permit published
  193.      * by the MCA wouldn't match...
  194.      */
  195.     if (!Local(from)) {
  196.     Rpc_Error(msg, RPC_ACCESS);
  197.     } if (len != sizeof(Host_Data)) {
  198.     Rpc_Error(msg, RPC_BADARGS);
  199.     } else if (Elect_InProgress() ||
  200.            ((host->flags & EXPORT_USELOCAL) &&
  201.         Avail_Local (~AVAIL_IDLE, &rating) == 0))
  202.     {
  203.            
  204.     /*
  205.      * If we're electing, or being nice and the local machine is
  206.      * available, barring keyboard idle time, of course, then
  207.      * send a failure message to the client -- the id field is
  208.      * unimportant in this case...
  209.      */
  210.     permit.addr.s_addr = INADDR_ANY;
  211.     Rpc_Return(msg, sizeof(permit), (Rpc_Opaque)&permit);
  212.     } else {
  213.     /*
  214.      * Ask the master where to go.
  215.      */
  216.     Rpc_Stat      rstat;
  217.  
  218.     rstat = Rpc_Call(udpSocket, &masterAddr, (Rpc_Proc)CUSTOMS_HOSTINT,
  219.              len, data, sizeof(permit), (Rpc_Opaque)&permit,
  220.              CUSTOMSINT_NRETRY, &retryTimeOut);
  221.     if (rstat != RPC_SUCCESS) {
  222.         permit.addr.s_addr = INADDR_ANY;
  223.         if (verbose) {
  224.         printf ("HostInt: %s\n", Rpc_ErrorMessage(rstat));
  225.         }
  226.     } else if (verbose) {
  227.         printf ("Host call generates %s response\n",
  228.             InetNtoA(permit.addr));
  229.     }
  230.     Rpc_Return(msg, sizeof(permit), (Rpc_Opaque)&permit);
  231.     if (rstat == RPC_TIMEDOUT) {
  232.         Elect_GetMaster();
  233.     }
  234.     }
  235. }
  236.  
  237. /*-
  238.  *-----------------------------------------------------------------------
  239.  * CustomsMaster --
  240.  *    Stub to handle CUSTOMS_MASTER procedure. Returns the address of
  241.  *    the current master agent.
  242.  *
  243.  * Results:
  244.  *    None.
  245.  *
  246.  * Side Effects:
  247.  *    The address of the master is sent to the client, or an RPC_TIMEDOUT
  248.  *    error is returned if an election is going on.
  249.  *
  250.  *-----------------------------------------------------------------------
  251.  */
  252. /*ARGSUSED*/
  253. static void
  254. CustomsMaster(from, msg, len, data)
  255.     struct sockaddr_in  *from;
  256.     Rpc_Message        msg;
  257.     int            len;
  258.     Rpc_Opaque           data;
  259. {
  260.     if (Elect_InProgress()) {
  261.     Rpc_Error(msg, RPC_TIMEDOUT);
  262.     } else {
  263.     Rpc_Return(msg, sizeof(masterAddr), (Rpc_Opaque)&masterAddr);
  264.     }
  265. }
  266.  
  267. /*-
  268.  *-----------------------------------------------------------------------
  269.  * CustomsAbort --
  270.  *    Abort this daemon. Returns nothing. Just exits.
  271.  *
  272.  * Results:
  273.  *    None.
  274.  *
  275.  * Side Effects:
  276.  *    The process exits.
  277.  *
  278.  *-----------------------------------------------------------------------
  279.  */
  280. /*ARGSUSED*/
  281. static void
  282. CustomsAbort(from, msg, len, data)
  283.     struct sockaddr_in  *from;
  284.     Rpc_Message        msg;
  285.     int            len;
  286.     Rpc_Opaque           data;
  287. {
  288.     Rpc_Return(msg, 0, (Rpc_Opaque)0);
  289.     
  290.     printf("Received ABORT message from %d@%s...\n",
  291.        ntohs(from->sin_port),
  292.        InetNtoA(from->sin_addr));
  293.     exit(0);
  294. }
  295.  
  296. /*-
  297.  *-----------------------------------------------------------------------
  298.  * CustomsRestart --
  299.  *    Re-execute ourselves using the original argument vector.
  300.  *
  301.  * Results:
  302.  *    None.
  303.  *
  304.  * Side Effects:
  305.  *    We reexecute.
  306.  *
  307.  *-----------------------------------------------------------------------
  308.  */
  309. /*ARGSUSED*/
  310. static void
  311. CustomsRestart(from, msg, len, data)
  312.     struct sockaddr_in    *from;
  313.     Rpc_Message          msg;
  314.     int                  len;
  315.     Rpc_Opaque          data;
  316. {
  317.     int                  i;
  318.     int                  fd = open("/dev/null", 0);
  319.  
  320.     Rpc_Return(msg, 0, (Rpc_Opaque)0);
  321.  
  322.     printf("Received RESTART from %d@%s\n", ntohs(from->sin_port),
  323.        InetNtoA(from->sin_addr));
  324.     printf("\texecuting: ");
  325.     for (i = 0; i < initARGC; i++) {
  326.     printf ("%s ", initARGV[i]);
  327.     }
  328.     printf("\n");
  329.     fflush(stdout);
  330.  
  331.     /*
  332.      * Make sure stdout and stdin are open to something so we don't close
  333.      * the sockets in our next life.
  334.      */
  335.     if (fd != 1) {
  336.     dup2(fd, 1);
  337.     }
  338.     if (fd != 2) {
  339.     dup2(fd, 2);
  340.     }
  341.     if (fd > 2) {
  342.     close(fd);
  343.     }
  344.     execvp(initARGV[0],initARGV);
  345. }
  346.  
  347. /*-
  348.  *-----------------------------------------------------------------------
  349.  * CustomsDebug --
  350.  *    Turn on debugging for us and/or the rpc system
  351.  *
  352.  * Results:
  353.  *    None.
  354.  *
  355.  * Side Effects:
  356.  *    verbose may be set true, as may rpcDebug.
  357.  *-----------------------------------------------------------------------
  358.  */
  359. /*ARGSUSED*/
  360. static void
  361. CustomsDebug(from, msg, len, data)
  362.     struct sockaddr_in    *from;
  363.     Rpc_Message          msg;
  364.     int                  len;
  365.     int                *data;
  366. {
  367.     Rpc_Debug(*data & DEBUG_RPC);
  368.     verbose = *data & DEBUG_CUSTOMS;
  369.  
  370.     Rpc_Return(msg, 0, (Rpc_Opaque)NULL);
  371. }
  372.  
  373. /*-
  374.  *-----------------------------------------------------------------------
  375.  * gettime --
  376.  *    Get a time value from a string. It must be in the form
  377.  *        mm:ss
  378.  *    where 'm' is a minute's digit and 's' is a second's degit.
  379.  *    neither number may be greater than 60, for obvious reasons.
  380.  *
  381.  * Results:
  382.  *
  383.  * Side Effects:
  384.  *
  385.  *-----------------------------------------------------------------------
  386.  */
  387. int
  388. gettime (str)
  389.     char    *str;
  390. {
  391.     int        min,
  392.         sec;
  393.  
  394.     for (min = 0;
  395.      *str != '\0' && *str != ':' ;
  396.      min = 10 * min + *str++ - '0') {
  397.          continue;
  398.     }
  399.     if (*str == '\0') {
  400.     sec = min;
  401.     min = 0;
  402.     } else {
  403.     for (sec = 0, str++; *str != '\0'; sec = 10 * sec + *str++ - '0') {
  404.         continue;
  405.     }
  406.     }
  407.     if (min >= 60 || sec >= 60) {
  408.     fprintf (stderr, "malformed time (only 60 seconds in a minute and 60 minutes in an hour)\n");
  409.     exit(1);
  410.     }
  411.     return (min * 60 + sec);
  412. }
  413.  
  414. void CustomsDebugOn() { verbose = TRUE; Rpc_Debug(True); }
  415. void CustomsDebugOff() { verbose = FALSE; Rpc_Debug(False); }
  416. /*-
  417.  *-----------------------------------------------------------------------
  418.  * Usage --
  419.  *    Print out the flags we accept and die.
  420.  *
  421.  * Results:
  422.  *    None.
  423.  *
  424.  * Side Effects:
  425.  *    The process exits.
  426.  *
  427.  *-----------------------------------------------------------------------
  428.  */
  429. void
  430. Usage ()
  431. {
  432.     printf ("Usage: customs <options> {host [host ...] | ALL }\n");
  433.     printf ("\t-verbose            Print verbose log messages\n");
  434.     printf ("\t-check <time>    Set availability check interval\n");
  435.     printf ("\t-idle <time>     Set minimum idle time\n");
  436.     printf ("\t-load <load avg>    Set maximum load average\n");
  437.     printf ("\t-swap <percent>    Set minimum free swap space\n");
  438.     printf ("\t-jobs <num>      Set maximum imported jobs\n");
  439.     printf ("\t-net <netnum>    Set customs network number\n");
  440.     printf ("\t-arch <archcode> Set customs architecture code\n");
  441.     exit(1);
  442. }
  443.  
  444. /*-
  445.  *-----------------------------------------------------------------------
  446.  * main --
  447.  *    Check the correctness of the arguments, look for an MCA and become
  448.  *    it if it doesn't exist, registering ourselves in the process.
  449.  *    Else register with the MCA and go into SCA mode.
  450.  *
  451.  * Results:
  452.  *    none.
  453.  *
  454.  * Side Effects:
  455.  *    Billions and Billions.
  456.  *
  457.  *-----------------------------------------------------------------------
  458.  */
  459. main (argc, argv)
  460.     int                  argc;
  461.     char              **argv;
  462. {
  463.     char              logName[256];
  464.     Boolean           doLog = TRUE;
  465.     Boolean           debug = FALSE;
  466.     Avail_Data          criteria;
  467.     int                  checkTime;
  468.     struct servent      *sep;
  469.     int            i;
  470.  
  471.     clients = (char **)malloc(sizeof(char *) * argc);
  472.     numClients = 0;
  473.  
  474.     initARGC = argc;
  475.     initARGV = argv;
  476.  
  477.     argc--, argv++;
  478.     criteria.changeMask = 0;
  479.     checkTime = 0;
  480.  
  481.     while (argc > 0) {
  482.     if (strcmp (*argv, "-verbose") == 0) {
  483.         verbose = TRUE;
  484.     } else if (strcmp (*argv, "-nolog") == 0) {
  485.         doLog = FALSE; debug = TRUE;
  486.     } else if (strcmp (*argv, "-debug") == 0) {
  487.         debug = TRUE;
  488.     } else if (strcmp (*argv, "-check") == 0) {
  489.         if (argc > 1) {
  490.         checkTime = gettime(argv[1]);
  491.         argc--;
  492.         argv++;
  493.         } else {
  494.         printf("-check needs a time as an argument\n");
  495.         Usage();
  496.         /*NOTREACHED*/
  497.         }
  498.     } else if (strcmp (*argv, "-idle") == 0) {
  499.         if (argc > 1) {
  500.         criteria.idleTime = gettime(argv[1]);
  501.         argc--;
  502.         argv++;
  503.         criteria.changeMask |= AVAIL_IDLE;
  504.         } else {
  505.         printf("-idle needs a time as an argument\n");
  506.         Usage();
  507.         /*NOTREACHED*/
  508.         }
  509.     } else if (strcmp (*argv, "-swap") == 0) {
  510.         if (argc > 1) {
  511.         criteria.swapPct = atoi(argv[1]);
  512.         argc--;
  513.         argv++;
  514.         criteria.changeMask |= AVAIL_SWAP;
  515.         } else {
  516.         printf("-swap needs a percentage as an argument\n");
  517.         Usage();
  518.         /*NOTREACHED*/
  519.         }
  520.     } else if (strcmp (*argv, "-load") == 0) {
  521.         double    maxLoad, atof();
  522.  
  523.         if (argc > 1) {
  524.         maxLoad = atof(argv[1]);
  525.         criteria.loadAvg = (int)(maxLoad * LOADSCALE);
  526.         criteria.changeMask |= AVAIL_LOAD;
  527.         argc--;
  528.         argv++;
  529.         } else {
  530.         printf("-load needs a load average as an argument\n");
  531.         Usage();
  532.         /*NOTREACHED*/
  533.         }
  534.     } else if (strcmp (*argv, "-jobs") == 0) {
  535.         if (argc > 1) {
  536.         criteria.imports = atoi(argv[1]);
  537.         argc--;
  538.         argv++;
  539.         criteria.changeMask |= AVAIL_IMPORTS;
  540.         } else {
  541.         printf("-jobs needs a number of jobs as an argument\n");
  542.         Usage();
  543.         /*NOTREACHED*/
  544.         }
  545.     } else if (strcmp (*argv, "-net") == 0) {
  546.         if (argc > 1) {
  547.         elect_Token = atoi(argv[1]);
  548.         argc--;
  549.         argv++;
  550.         } else {
  551.         printf("-net needs a network number for an argument\n");
  552.         Usage();
  553.         /*NOTREACHED*/
  554.         }
  555.     } else if (strcmp (*argv, "-arch") == 0) {
  556.         if (argc > 1) {
  557.         arch = atoi(argv[1]);
  558.         argc--;
  559.         argv++;
  560.         } else {
  561.         printf("-arch needs an architecture code for an argument\n");
  562.         Usage();
  563.         /*NOTREACHED*/
  564.         }
  565.     } else if (strcmp(*argv, "-bias") == 0) {
  566.         if (argc > 1) {
  567.         avail_Bias = atoi(argv[1]);
  568.         argc--;
  569.         argv++;
  570.         } else {
  571.         printf("-bias needs a bias value for an argument\n");
  572.         Usage();
  573.         /*NOTREACHED*/
  574.         }
  575.     } else if (**argv == '-') {
  576.         printf ("Unknown option %s\n", *argv);
  577.         Usage();
  578.         /*NOTREACHED*/
  579.     } else {
  580.         clients[numClients] = *argv;
  581.         numClients += 1;
  582.     }
  583.     argc--; argv++;
  584.     }
  585.  
  586.     if (numClients == 0) {
  587.     printf ("You must serve at least one host!\n");
  588.     exit(1);
  589.     }
  590.     
  591.     if (!debug) {
  592.     int t,
  593.         pid;
  594.  
  595.     /*
  596.      * First detach from our parent, then from the tty...
  597.      */
  598.     pid = fork();
  599.     if (pid == -1) {
  600.         perror("fork");
  601.     }
  602.     if (pid != 0) {
  603.         exit(0);
  604.     }
  605.  
  606.     t = open ("/dev/tty", O_RDWR, 0);
  607.     if (t >= 0) {
  608.         ioctl (t, TIOCNOTTY, 0);
  609.         (void) close (t);
  610.     }
  611.  
  612.     if (getuid() || geteuid()) {
  613.         printf ("This program must be run as root to execute properly\n");
  614.         exit(1);
  615.     }
  616.  
  617.     /*
  618.      * Renice the main server so it can respond to calls even if four
  619.      * of its jobs are running...
  620.      */
  621.     if (setpriority(PRIO_PROCESS, getpid(), -2) < 0) {
  622.         perror("setpriority");
  623.     }
  624.     }
  625.     
  626.     if (gethostname (localhost, MACHINE_NAME_SIZE)) {
  627.     printf ("The name of this machine is too long (%d chars max)\n",
  628.           MACHINE_NAME_SIZE);
  629.     exit(1);
  630.     }
  631.  
  632.     if (doLog) {
  633.     char *cp = index (localhost, '.');
  634.     if (cp) {
  635.         *cp = '\0';
  636.     }
  637.     sprintf (logName, "%s.%s", LOG_BASE, localhost);
  638.     freopen (logName, "a", stdout);
  639.     if (cp) {
  640.         *cp = '.';
  641.     }
  642.     fcntl(1, F_SETFL, FAPPEND);
  643.     }
  644.  
  645.     for (i = 3; i > 0; i--) {
  646.     sep = getservbyname("customs", "udp");
  647.     if (sep != NULL) {
  648.         sleep(2);
  649.     } else {
  650.         break;
  651.     }
  652.     }
  653.     if (sep == NULL) {
  654.     printf("customs/udp (still) unknown\n");
  655.     udpPort = DEF_CUSTOMS_UDP_PORT;
  656.     } else {
  657.     udpPort = sep->s_port;
  658.     }
  659.     udpSocket = Rpc_UdpCreate(True, udpPort);
  660.     if (udpSocket < 0) {
  661.     perror ("Rpc_UdpCreate");
  662.     exit(1);
  663.     }
  664.  
  665.     for (i = 3; i > 0; i--) {
  666.     sep = getservbyname("customs", "tcp");
  667.     if (sep != NULL) {
  668.         sleep(2);
  669.     } else {
  670.         break;
  671.     }
  672.     }
  673.     if (sep == NULL) {
  674.     printf("customs/tcp (still) unknown\n");
  675.     tcpPort = DEF_CUSTOMS_TCP_PORT;
  676.     } else {
  677.     tcpPort = sep->s_port;
  678.     }
  679.     tcpSocket = Rpc_TcpCreate(True, tcpPort);
  680.     if (tcpSocket < 0) {
  681.     perror("Rpc_TcpCreate");
  682.     exit(1);
  683.     }
  684.     /*
  685.      * Mark both service sockets as close on exec.
  686.      */
  687.     (void)fcntl (udpSocket, F_SETFD, 1);
  688.     (void)fcntl (tcpSocket, F_SETFD, 1);
  689.  
  690.     /*
  691.      * Register all the servers every agent must handle
  692.      */
  693.     Rpc_ServerCreate(udpSocket, (Rpc_Proc)CUSTOMS_PING, CustomsPing,
  694.              Rpc_SwapNull, Rpc_SwapNull, (Rpc_Opaque)0);
  695.     Rpc_ServerCreate(udpSocket, (Rpc_Proc)CUSTOMS_HOST, CustomsHost,
  696.              Swap_Host, Swap_ExportPermit, (Rpc_Opaque)0);
  697.     Rpc_ServerCreate(udpSocket, (Rpc_Proc)CUSTOMS_MASTER, CustomsMaster,
  698.              Rpc_SwapNull, Rpc_SwapLong, (Rpc_Opaque)0);
  699.     Rpc_ServerCreate(udpSocket, (Rpc_Proc)CUSTOMS_ABORT, CustomsAbort,
  700.              Rpc_SwapNull, Rpc_SwapNull, (Rpc_Opaque)0);
  701.     Rpc_ServerCreate(tcpSocket, (Rpc_Proc)CUSTOMS_ABORT, CustomsAbort,
  702.              Rpc_SwapNull, Rpc_SwapNull, (Rpc_Opaque)0);
  703.     Rpc_ServerCreate(udpSocket, (Rpc_Proc)CUSTOMS_RESTART, CustomsRestart,
  704.              Rpc_SwapNull, Rpc_SwapNull, (Rpc_Opaque)0);
  705.     Rpc_ServerCreate(udpSocket, (Rpc_Proc)CUSTOMS_DEBUG, CustomsDebug,
  706.              Rpc_SwapLong, Rpc_SwapNull, (Rpc_Opaque)0);
  707.     
  708.     signal(30, CustomsDebugOn);
  709.     signal(31, CustomsDebugOff);
  710.     
  711.     /*
  712.      * Close stdin and stderr so the descriptors are reused by the Avail
  713.      * module. Note that if the Avail module changes to use fewer than two
  714.      * descriptors, you should leave one of these things open so the Import
  715.      * module doesn't have to worry about its socket already being in the
  716.      * right place (dup2 (0, 0) would probably not be cool...)
  717.      */
  718.     fclose (stdin);
  719.     fclose (stderr);
  720.  
  721.     /*
  722.      * XXX: There should be some way to actually share these things so
  723.      * all the perror-type functions would play with the same things.
  724.      * unfortunately, stderr and stdout are macros, so we can only
  725.      * get around things by making stdout be unbuffered...
  726.      */
  727.     setbuf (stdout, (char *)NULL);
  728.     *stderr = *stdout;
  729.     
  730.     /*
  731.      * Find the local address. get_myaddress is actually from Sun RPC
  732.      * functions, but...
  733.      */
  734.     get_myaddress(&localAddr);
  735.     localAddr.sin_port = udpPort;
  736.     if (verbose) {
  737.     printf ("local address: %d@%s\n",
  738.         localAddr.sin_port,
  739.         InetNtoA(localAddr.sin_addr));
  740.     }
  741.  
  742.     MakeRegistrationPacket();
  743.  
  744.     Log_Init();
  745.     Avail_Init(&criteria, checkTime);
  746.     Import_Init();
  747.     Elect_Init();
  748.     Elect_GetMaster();
  749.  
  750.     Rpc_Run();
  751. }
  752.  
  753. perror(str)
  754.     char *str;
  755. {
  756.     extern int errno;
  757.     extern char *sys_errlist[];
  758.     extern int sys_nerr;
  759.  
  760.     if (errno > sys_nerr) {
  761.     printf("%s: %d\n", str, errno);
  762.     } else {
  763.     printf("%s: %s\n", str, sys_errlist[errno]);
  764.     }
  765. }
  766.